home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / win / tkWinDraw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  32.2 KB  |  1,265 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkWinDraw.c --
  3.  *
  4.  *    This file contains the Xlib emulation functions pertaining to
  5.  *    actually drawing objects on a window.
  6.  *
  7.  * Copyright (c) 1995 Sun Microsystems, Inc.
  8.  * Copyright (c) 1994 Software Research Associates, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * SCCS: @(#) tkWinDraw.c 1.30 97/03/21 11:20:05
  14.  */
  15.  
  16. #include "tkWinInt.h"
  17.  
  18. /*
  19.  * These macros convert between X's bizarre angle units to radians.
  20.  */
  21.  
  22. #define PI 3.14159265358979
  23. #define XAngleToRadians(a) ((double)(a) / 64 * PI / 180);
  24.  
  25. /*
  26.  * Translation table between X gc functions and Win32 raster op modes.
  27.  */
  28.  
  29. int tkpWinRopModes[] = {
  30.     R2_BLACK,            /* GXclear */
  31.     R2_MASKPEN,            /* GXand */
  32.     R2_MASKPENNOT,        /* GXandReverse */
  33.     R2_COPYPEN,            /* GXcopy */
  34.     R2_MASKNOTPEN,        /* GXandInverted */
  35.     R2_NOT,            /* GXnoop */
  36.     R2_XORPEN,            /* GXxor */
  37.     R2_MERGEPEN,        /* GXor */
  38.     R2_NOTMERGEPEN,        /* GXnor */
  39.     R2_NOTXORPEN,        /* GXequiv */
  40.     R2_NOT,            /* GXinvert */
  41.     R2_MERGEPENNOT,        /* GXorReverse */
  42.     R2_NOTCOPYPEN,        /* GXcopyInverted */
  43.     R2_MERGENOTPEN,        /* GXorInverted */
  44.     R2_NOTMASKPEN,        /* GXnand */
  45.     R2_WHITE            /* GXset */
  46. };
  47.  
  48. /*
  49.  * Translation table between X gc functions and Win32 BitBlt op modes.  Some
  50.  * of the operations defined in X don't have names, so we have to construct
  51.  * new opcodes for those functions.  This is arcane and probably not all that
  52.  * useful, but at least it's accurate.
  53.  */
  54.  
  55. #define NOTSRCAND    (DWORD)0x00220326 /* dest = (NOT source) AND dest */
  56. #define NOTSRCINVERT    (DWORD)0x00990066 /* dest = (NOT source) XOR dest */
  57. #define SRCORREVERSE    (DWORD)0x00DD0228 /* dest = source OR (NOT dest) */
  58. #define SRCNAND        (DWORD)0x007700E6 /* dest = NOT (source AND dest) */
  59.  
  60. static int bltModes[] = {
  61.     BLACKNESS,            /* GXclear */
  62.     SRCAND,            /* GXand */
  63.     SRCERASE,            /* GXandReverse */
  64.     SRCCOPY,            /* GXcopy */
  65.     NOTSRCAND,            /* GXandInverted */
  66.     PATCOPY,            /* GXnoop */
  67.     SRCINVERT,            /* GXxor */
  68.     SRCPAINT,            /* GXor */
  69.     NOTSRCERASE,        /* GXnor */
  70.     NOTSRCINVERT,        /* GXequiv */
  71.     DSTINVERT,            /* GXinvert */
  72.     SRCORREVERSE,        /* GXorReverse */
  73.     NOTSRCCOPY,            /* GXcopyInverted */
  74.     MERGEPAINT,            /* GXorInverted */
  75.     SRCNAND,            /* GXnand */
  76.     WHITENESS            /* GXset */
  77. };
  78.  
  79. /*
  80.  * The following raster op uses the source bitmap as a mask for the
  81.  * pattern.  This is used to draw in a foreground color but leave the
  82.  * background color transparent.
  83.  */
  84.  
  85. #define MASKPAT        0x00E20746 /* dest = (src & pat) | (!src & dst) */
  86.  
  87. /*
  88.  * The following two raster ops are used to copy the foreground and background
  89.  * bits of a source pattern as defined by a stipple used as the pattern.
  90.  */
  91.  
  92. #define COPYFG        0x00CA0749 /* dest = (pat & src) | (!pat & dst) */
  93. #define COPYBG        0x00AC0744 /* dest = (!pat & src) | (pat & dst) */
  94.  
  95. /*
  96.  * Macros used later in the file.
  97.  */
  98.  
  99. #define MIN(a,b)    ((a>b) ? b : a)
  100. #define MAX(a,b)    ((a<b) ? b : a)
  101.  
  102. /*
  103.  * The followng typedef is used to pass Windows GDI drawing functions.
  104.  */
  105.  
  106. typedef BOOL (CALLBACK *WinDrawFunc) _ANSI_ARGS_((HDC dc,
  107.                 CONST POINT* points, int npoints));
  108.  
  109. /*
  110.  * Forward declarations for procedures defined in this file:
  111.  */
  112.  
  113. static POINT *        ConvertPoints _ANSI_ARGS_((XPoint *points, int npoints,
  114.                 int mode, RECT *bbox));
  115. static void        DrawOrFillArc _ANSI_ARGS_((Display *display,
  116.                 Drawable d, GC gc, int x, int y,
  117.                 unsigned int width, unsigned int height,
  118.                 int start, int extent, int fill));
  119. static void        RenderObject _ANSI_ARGS_((HDC dc, GC gc,
  120.                 XPoint* points, int npoints, int mode, HPEN pen,
  121.                 WinDrawFunc func));
  122.  
  123. /*
  124.  *----------------------------------------------------------------------
  125.  *
  126.  * TkWinGetDrawableDC --
  127.  *
  128.  *    Retrieve the DC from a drawable.
  129.  *
  130.  * Results:
  131.  *    Returns the window DC for windows.  Returns a new memory DC
  132.  *    for pixmaps.
  133.  *
  134.  * Side effects:
  135.  *    Sets up the palette for the device context, and saves the old
  136.  *    device context state in the passed in TkWinDCState structure.
  137.  *
  138.  *----------------------------------------------------------------------
  139.  */
  140.  
  141. HDC
  142. TkWinGetDrawableDC(display, d, state)
  143.     Display *display;
  144.     Drawable d;
  145.     TkWinDCState* state;
  146. {
  147.     HDC dc;
  148.     TkWinDrawable *twdPtr = (TkWinDrawable *)d;
  149.     Colormap cmap;
  150.  
  151.     if (twdPtr->type == TWD_WINDOW) {
  152.     TkWindow *winPtr = twdPtr->window.winPtr;
  153.     
  154.      dc = GetDC(twdPtr->window.handle);
  155.     if (winPtr == NULL) {
  156.         cmap = DefaultColormap(display, DefaultScreen(display));
  157.     } else {
  158.         cmap = winPtr->atts.colormap;
  159.     }
  160.     } else if (twdPtr->type == TWD_WINDC) {
  161.     dc = twdPtr->winDC.hdc;
  162.     cmap = DefaultColormap(display, DefaultScreen(display));
  163.     } else {
  164.     dc = CreateCompatibleDC(NULL);
  165.     SelectObject(dc, twdPtr->bitmap.handle);
  166.     cmap = twdPtr->bitmap.colormap;
  167.     }
  168.     state->palette = TkWinSelectPalette(dc, cmap);
  169.     return dc;
  170. }
  171.  
  172. /*
  173.  *----------------------------------------------------------------------
  174.  *
  175.  * TkWinReleaseDrawableDC --
  176.  *
  177.  *    Frees the resources associated with a drawable's DC.
  178.  *
  179.  * Results:
  180.  *    None.
  181.  *
  182.  * Side effects:
  183.  *    Restores the old bitmap handle to the memory DC for pixmaps.
  184.  *
  185.  *----------------------------------------------------------------------
  186.  */
  187.  
  188. void
  189. TkWinReleaseDrawableDC(d, dc, state)
  190.     Drawable d;
  191.     HDC dc;
  192.     TkWinDCState *state;
  193. {
  194.     TkWinDrawable *twdPtr = (TkWinDrawable *)d;
  195.     SelectPalette(dc, state->palette, TRUE);
  196.     RealizePalette(dc);
  197.     if (twdPtr->type == TWD_WINDOW) {
  198.     ReleaseDC(TkWinGetHWND(d), dc);
  199.     } else if (twdPtr->type == TWD_BITMAP) {
  200.     DeleteDC(dc);
  201.     }
  202. }
  203.  
  204. /*
  205.  *----------------------------------------------------------------------
  206.  *
  207.  * ConvertPoints --
  208.  *
  209.  *    Convert an array of X points to an array of Win32 points.
  210.  *
  211.  * Results:
  212.  *    Returns the converted array of POINTs.
  213.  *
  214.  * Side effects:
  215.  *    Allocates a block of memory that should not be freed.
  216.  *
  217.  *----------------------------------------------------------------------
  218.  */
  219.  
  220. static POINT *
  221. ConvertPoints(points, npoints, mode, bbox)
  222.     XPoint *points;
  223.     int npoints;
  224.     int mode;            /* CoordModeOrigin or CoordModePrevious. */
  225.     RECT *bbox;            /* Bounding box of points. */
  226. {
  227.     static POINT *winPoints = NULL; /* Array of points that is reused. */
  228.     static int nWinPoints = -1;        /* Current size of point array. */
  229.     int i;
  230.  
  231.     /*
  232.      * To avoid paying the cost of a malloc on every drawing routine,
  233.      * we reuse the last array if it is large enough.
  234.      */
  235.  
  236.     if (npoints > nWinPoints) {
  237.     if (winPoints != NULL) {
  238.         ckfree((char *) winPoints);
  239.     }
  240.     winPoints = (POINT *) ckalloc(sizeof(POINT) * npoints);
  241.     if (winPoints == NULL) {
  242.         nWinPoints = -1;
  243.         return NULL;
  244.     }
  245.     nWinPoints = npoints;
  246.     }
  247.  
  248.     bbox->left = bbox->right = points[0].x;
  249.     bbox->top = bbox->bottom = points[0].y;
  250.     
  251.     if (mode == CoordModeOrigin) {
  252.     for (i = 0; i < npoints; i++) {
  253.         winPoints[i].x = points[i].x;
  254.         winPoints[i].y = points[i].y;
  255.         bbox->left = MIN(bbox->left, winPoints[i].x);
  256.         bbox->right = MAX(bbox->right, winPoints[i].x);
  257.         bbox->top = MIN(bbox->top, winPoints[i].y);
  258.         bbox->bottom = MAX(bbox->bottom, winPoints[i].y);
  259.     }
  260.     } else {
  261.     winPoints[0].x = points[0].x;
  262.     winPoints[0].y = points[0].y;
  263.     for (i = 1; i < npoints; i++) {
  264.         winPoints[i].x = winPoints[i-1].x + points[i].x;
  265.         winPoints[i].y = winPoints[i-1].y + points[i].y;
  266.         bbox->left = MIN(bbox->left, winPoints[i].x);
  267.         bbox->right = MAX(bbox->right, winPoints[i].x);
  268.         bbox->top = MIN(bbox->top, winPoints[i].y);
  269.         bbox->bottom = MAX(bbox->bottom, winPoints[i].y);
  270.     }
  271.     }
  272.     return winPoints;
  273. }
  274.  
  275. /*
  276.  *----------------------------------------------------------------------
  277.  *
  278.  * XCopyArea --
  279.  *
  280.  *    Copies data from one drawable to another using block transfer
  281.  *    routines.
  282.  *
  283.  * Results:
  284.  *    None.
  285.  *
  286.  * Side effects:
  287.  *    Data is moved from a window or bitmap to a second window or
  288.  *    bitmap.
  289.  *
  290.  *----------------------------------------------------------------------
  291.  */
  292.  
  293. void
  294. XCopyArea(display, src, dest, gc, src_x, src_y, width, height, dest_x, dest_y)
  295.     Display* display;
  296.     Drawable src;
  297.     Drawable dest;
  298.     GC gc;
  299.     int src_x, src_y;
  300.     unsigned int width, height;
  301.     int dest_x, dest_y;
  302. {
  303.     HDC srcDC, destDC;
  304.     TkWinDCState srcState, destState;
  305.     TkpClipMask *clipPtr = (TkpClipMask*)gc->clip_mask;
  306.  
  307.     srcDC = TkWinGetDrawableDC(display, src, &srcState);
  308.  
  309.     if (src != dest) {
  310.     destDC = TkWinGetDrawableDC(display, dest, &destState);
  311.     } else {
  312.     destDC = srcDC;
  313.     }
  314.  
  315.     if (clipPtr && clipPtr->type == TKP_CLIP_REGION) {
  316.     SelectClipRgn(destDC, (HRGN) clipPtr->value.region);
  317.     OffsetClipRgn(destDC, gc->clip_x_origin, gc->clip_y_origin);
  318.     }
  319.  
  320.     BitBlt(destDC, dest_x, dest_y, width, height, srcDC, src_x, src_y,
  321.         bltModes[gc->function]);
  322.  
  323.     SelectClipRgn(destDC, NULL);
  324.  
  325.     if (src != dest) {
  326.     TkWinReleaseDrawableDC(dest, destDC, &destState);
  327.     }
  328.     TkWinReleaseDrawableDC(src, srcDC, &srcState);
  329. }
  330.  
  331. /*
  332.  *----------------------------------------------------------------------
  333.  *
  334.  * XCopyPlane --
  335.  *
  336.  *    Copies a bitmap from a source drawable to a destination
  337.  *    drawable.  The plane argument specifies which bit plane of
  338.  *    the source contains the bitmap.  Note that this implementation
  339.  *    ignores the gc->function.
  340.  *
  341.  * Results:
  342.  *    None.
  343.  *
  344.  * Side effects:
  345.  *    Changes the destination drawable.
  346.  *
  347.  *----------------------------------------------------------------------
  348.  */
  349.  
  350. void
  351. XCopyPlane(display, src, dest, gc, src_x, src_y, width, height, dest_x,
  352.     dest_y, plane)
  353.     Display* display;
  354.     Drawable src;
  355.     Drawable dest;
  356.     GC gc;
  357.     int src_x, src_y;
  358.     unsigned int width, height;
  359.     int dest_x, dest_y;
  360.     unsigned long plane;
  361. {
  362.     HDC srcDC, destDC;
  363.     TkWinDCState srcState, destState;
  364.     HBRUSH bgBrush, fgBrush, oldBrush;
  365.     TkpClipMask *clipPtr = (TkpClipMask*)gc->clip_mask;
  366.  
  367.     display->request++;
  368.  
  369.     if (plane != 1) {
  370.     panic("Unexpected plane specified for XCopyPlane");
  371.     }
  372.  
  373.     srcDC = TkWinGetDrawableDC(display, src, &srcState);
  374.  
  375.     if (src != dest) {
  376.     destDC = TkWinGetDrawableDC(display, dest, &destState);
  377.     } else {
  378.     destDC = srcDC;
  379.     }
  380.  
  381.     if (clipPtr == NULL || clipPtr->type == TKP_CLIP_REGION) {
  382.  
  383.     /*
  384.      * Case 1: opaque bitmaps.  Windows handles the conversion
  385.      * from one bit to multiple bits by setting 0 to the
  386.      * foreground color, and 1 to the background color (seems
  387.      * backwards, but there you are).
  388.      */
  389.  
  390.     if (clipPtr && clipPtr->type == TKP_CLIP_REGION) {
  391.         SelectClipRgn(destDC, (HRGN) clipPtr->value.region);
  392.         OffsetClipRgn(destDC, gc->clip_x_origin, gc->clip_y_origin);
  393.     }
  394.  
  395.     SetBkMode(destDC, OPAQUE);
  396.     SetBkColor(destDC, gc->foreground);
  397.     SetTextColor(destDC, gc->background);
  398.     BitBlt(destDC, dest_x, dest_y, width, height, srcDC, src_x, src_y,
  399.         SRCCOPY);
  400.  
  401.     SelectClipRgn(destDC, NULL);
  402.     } else if (clipPtr->type == TKP_CLIP_PIXMAP) {
  403.     if (clipPtr->value.pixmap == src) {
  404.  
  405.         /*
  406.          * Case 2: transparent bitmaps are handled by setting the
  407.          * destination to the foreground color whenever the source
  408.          * pixel is set.
  409.          */
  410.  
  411.         fgBrush = CreateSolidBrush(gc->foreground);
  412.         oldBrush = SelectObject(destDC, fgBrush);
  413.         BitBlt(destDC, dest_x, dest_y, width, height, srcDC, src_x, src_y,
  414.             MASKPAT);
  415.         SelectObject(destDC, oldBrush);
  416.         DeleteObject(fgBrush);
  417.     } else {
  418.  
  419.         /*
  420.          * Case 3: two arbitrary bitmaps.  Copy the source rectangle
  421.          * into a color pixmap.  Use the result as a brush when
  422.          * copying the clip mask into the destination.     
  423.          */
  424.  
  425.         HDC memDC, maskDC;
  426.         HBITMAP bitmap;
  427.         TkWinDCState maskState;
  428.  
  429.         fgBrush = CreateSolidBrush(gc->foreground);
  430.         bgBrush = CreateSolidBrush(gc->background);
  431.         maskDC = TkWinGetDrawableDC(display, clipPtr->value.pixmap,
  432.             &maskState);
  433.         memDC = CreateCompatibleDC(destDC);
  434.         bitmap = CreateBitmap(width, height, 1, 1, NULL);
  435.         SelectObject(memDC, bitmap);
  436.  
  437.         /*
  438.          * Set foreground bits.  We create a new bitmap containing
  439.          * (source AND mask), then use it to set the foreground color
  440.          * into the destination.
  441.          */
  442.  
  443.         BitBlt(memDC, 0, 0, width, height, srcDC, src_x, src_y, SRCCOPY);
  444.         BitBlt(memDC, 0, 0, width, height, maskDC,
  445.             dest_x - gc->clip_x_origin, dest_y - gc->clip_y_origin,
  446.             SRCAND);
  447.         oldBrush = SelectObject(destDC, fgBrush);
  448.         BitBlt(destDC, dest_x, dest_y, width, height, memDC, 0, 0,
  449.             MASKPAT);
  450.  
  451.         /*
  452.          * Set background bits.  Same as foreground, except we use
  453.          * ((NOT source) AND mask) and the background brush.
  454.          */
  455.  
  456.         BitBlt(memDC, 0, 0, width, height, srcDC, src_x, src_y,
  457.             NOTSRCCOPY);
  458.         BitBlt(memDC, 0, 0, width, height, maskDC,
  459.             dest_x - gc->clip_x_origin, dest_y - gc->clip_y_origin,
  460.             SRCAND);
  461.         SelectObject(destDC, bgBrush);
  462.         BitBlt(destDC, dest_x, dest_y, width, height, memDC, 0, 0,
  463.             MASKPAT);
  464.  
  465.         TkWinReleaseDrawableDC(clipPtr->value.pixmap, maskDC, &maskState);
  466.         SelectObject(destDC, oldBrush);
  467.         DeleteDC(memDC);
  468.         DeleteObject(bitmap);
  469.         DeleteObject(fgBrush);
  470.         DeleteObject(bgBrush);
  471.     }
  472.     }
  473.     if (src != dest) {
  474.     TkWinReleaseDrawableDC(dest, destDC, &destState);
  475.     }
  476.     TkWinReleaseDrawableDC(src, srcDC, &srcState);
  477. }
  478.  
  479. /*
  480.  *----------------------------------------------------------------------
  481.  *
  482.  * TkPutImage --
  483.  *
  484.  *    Copies a subimage from an in-memory image to a rectangle of
  485.  *    of the specified drawable.
  486.  *
  487.  * Results:
  488.  *    None.
  489.  *
  490.  * Side effects:
  491.  *    Draws the image on the specified drawable.
  492.  *
  493.  *----------------------------------------------------------------------
  494.  */
  495.  
  496. void
  497. TkPutImage(colors, ncolors, display, d, gc, image, src_x, src_y, dest_x,
  498.     dest_y, width, height)
  499.     unsigned long *colors;        /* Array of pixel values used by this
  500.                      * image.  May be NULL. */
  501.     int ncolors;            /* Number of colors used, or 0. */
  502.     Display* display;
  503.     Drawable d;                /* Destination drawable. */
  504.     GC gc;
  505.     XImage* image;            /* Source image. */
  506.     int src_x, src_y;            /* Offset of subimage. */      
  507.     int dest_x, dest_y;            /* Position of subimage origin in
  508.                      * drawable.  */
  509.     unsigned int width, height;        /* Dimensions of subimage. */
  510. {
  511.     HDC dc, dcMem;
  512.     TkWinDCState state;
  513.     BITMAPINFO *infoPtr;
  514.     HBITMAP bitmap;
  515.     char *data;
  516.  
  517.     display->request++;
  518.  
  519.     dc = TkWinGetDrawableDC(display, d, &state);
  520.     SetROP2(dc, tkpWinRopModes[gc->function]);
  521.     dcMem = CreateCompatibleDC(dc);
  522.  
  523.     if (image->bits_per_pixel == 1) {
  524.     /*
  525.      * If the image isn't in the right format, we have to copy
  526.      * it into a new buffer in MSBFirst and word-aligned format.
  527.      */
  528.  
  529.     if ((image->bitmap_bit_order != MSBFirst)
  530.         || (image->bitmap_pad != sizeof(WORD))) {
  531.         data = TkAlignImageData(image, sizeof(WORD), MSBFirst);
  532.         bitmap = CreateBitmap(image->width, image->height, 1, 1, data);
  533.         ckfree(data);
  534.     } else {
  535.         bitmap = CreateBitmap(image->width, image->height, 1, 1,
  536.             image->data);
  537.     }
  538.     SetTextColor(dc, gc->foreground);
  539.     SetBkColor(dc, gc->background);
  540.     } else {    
  541.     int i, usePalette;
  542.  
  543.     /*
  544.      * Do not use a palette for TrueColor images.
  545.      */
  546.     
  547.     usePalette = (image->bits_per_pixel < 16);
  548.     
  549.     if (usePalette) {
  550.         infoPtr = (BITMAPINFO*) ckalloc(sizeof(BITMAPINFOHEADER)
  551.             + sizeof(RGBQUAD)*ncolors);
  552.     } else {
  553.         infoPtr = (BITMAPINFO*) ckalloc(sizeof(BITMAPINFOHEADER));
  554.     }
  555.     
  556.     infoPtr->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  557.     infoPtr->bmiHeader.biWidth = image->width;
  558.  
  559.     /*
  560.      * The following code works around a bug in Win32s.  CreateDIBitmap
  561.      * fails under Win32s for top-down images.  So we have to reverse the
  562.      * order of the scanlines.  If we are not running under Win32s, we can
  563.      * just declare the image to be top-down.
  564.      */
  565.  
  566.     if (tkpIsWin32s) {
  567.         int y;
  568.         char *srcPtr, *dstPtr, *temp;
  569.  
  570.         temp = ckalloc((unsigned) image->bytes_per_line);
  571.         srcPtr = image->data;
  572.         dstPtr = image->data+(image->bytes_per_line * (image->height - 1));
  573.         for (y = 0; y < (image->height/2); y++) {
  574.         memcpy(temp, srcPtr, image->bytes_per_line);
  575.         memcpy(srcPtr, dstPtr, image->bytes_per_line);
  576.         memcpy(dstPtr, temp, image->bytes_per_line);
  577.         srcPtr += image->bytes_per_line;
  578.         dstPtr -= image->bytes_per_line;
  579.         }
  580.         ckfree(temp);
  581.         infoPtr->bmiHeader.biHeight = image->height; /* Bottom-up order */
  582.     } else {
  583.         infoPtr->bmiHeader.biHeight = -image->height; /* Top-down order */
  584.     }
  585.     infoPtr->bmiHeader.biPlanes = 1;
  586.     infoPtr->bmiHeader.biBitCount = image->bits_per_pixel;
  587.     infoPtr->bmiHeader.biCompression = BI_RGB;
  588.     infoPtr->bmiHeader.biSizeImage = 0;
  589.     infoPtr->bmiHeader.biXPelsPerMeter = 0;
  590.     infoPtr->bmiHeader.biYPelsPerMeter = 0;
  591.     infoPtr->bmiHeader.biClrImportant = 0;
  592.  
  593.     if (usePalette) {
  594.         infoPtr->bmiHeader.biClrUsed = ncolors;
  595.         for (i = 0; i < ncolors; i++) {
  596.         infoPtr->bmiColors[i].rgbBlue = GetBValue(colors[i]);
  597.         infoPtr->bmiColors[i].rgbGreen = GetGValue(colors[i]);
  598.         infoPtr->bmiColors[i].rgbRed = GetRValue(colors[i]);
  599.         infoPtr->bmiColors[i].rgbReserved = 0;
  600.         }
  601.     } else {
  602.         infoPtr->bmiHeader.biClrUsed = 0;
  603.     }
  604.     bitmap = CreateDIBitmap(dc, &infoPtr->bmiHeader, CBM_INIT,
  605.         image->data, infoPtr, DIB_RGB_COLORS);
  606.     ckfree((char *) infoPtr);
  607.     }
  608.     bitmap = SelectObject(dcMem, bitmap);
  609.     BitBlt(dc, dest_x, dest_y, width, height, dcMem, src_x, src_y, SRCCOPY);
  610.     DeleteObject(SelectObject(dcMem, bitmap));
  611.     DeleteDC(dcMem);
  612.     TkWinReleaseDrawableDC(d, dc, &state);
  613. }
  614.  
  615. /*
  616.  *----------------------------------------------------------------------
  617.  *
  618.  * XFillRectangles --
  619.  *
  620.  *    Fill multiple rectangular areas in the given drawable.
  621.  *
  622.  * Results:
  623.  *    None.
  624.  *
  625.  * Side effects:
  626.  *    Draws onto the specified drawable.
  627.  *
  628.  *----------------------------------------------------------------------
  629.  */
  630.  
  631. void
  632. XFillRectangles(display, d, gc, rectangles, nrectangles)
  633.     Display* display;
  634.     Drawable d;
  635.     GC gc;
  636.     XRectangle* rectangles;
  637.     int nrectangles;
  638. {
  639.     HDC dc;
  640.     int i;
  641.     RECT rect;
  642.     TkWinDCState state;
  643.     HBRUSH brush;
  644.  
  645.     if (d == None) {
  646.     return;
  647.     }
  648.  
  649.     dc = TkWinGetDrawableDC(display, d, &state);
  650.     SetROP2(dc, tkpWinRopModes[gc->function]);
  651.     brush = CreateSolidBrush(gc->foreground);
  652.  
  653.     if ((gc->fill_style == FillStippled
  654.         || gc->fill_style == FillOpaqueStippled)
  655.         && gc->stipple != None) {
  656.     TkWinDrawable *twdPtr = (TkWinDrawable *)gc->stipple;
  657.     HBRUSH oldBrush, stipple;
  658.     HBITMAP oldBitmap, bitmap;
  659.     HDC dcMem;
  660.     HBRUSH bgBrush = CreateSolidBrush(gc->background);
  661.  
  662.     if (twdPtr->type != TWD_BITMAP) {
  663.         panic("unexpected drawable type in stipple");
  664.     }
  665.  
  666.     /*
  667.      * Select stipple pattern into destination dc.
  668.      */
  669.     
  670.     stipple = CreatePatternBrush(twdPtr->bitmap.handle);
  671.     SetBrushOrgEx(dc, gc->ts_x_origin, gc->ts_y_origin, NULL);
  672.     oldBrush = SelectObject(dc, stipple);
  673.     dcMem = CreateCompatibleDC(dc);
  674.  
  675.     /*
  676.      * For each rectangle, create a drawing surface which is the size of
  677.      * the rectangle and fill it with the background color.  Then merge the
  678.      * result with the stipple pattern.
  679.      */
  680.  
  681.     for (i = 0; i < nrectangles; i++) {
  682.         bitmap = CreateCompatibleBitmap(dc, rectangles[i].width,
  683.             rectangles[i].height);
  684.         oldBitmap = SelectObject(dcMem, bitmap);
  685.         rect.left = 0;
  686.         rect.top = 0;
  687.         rect.right = rectangles[i].width;
  688.         rect.bottom = rectangles[i].height;
  689.         FillRect(dcMem, &rect, brush);
  690.         BitBlt(dc, rectangles[i].x, rectangles[i].y, rectangles[i].width,
  691.             rectangles[i].height, dcMem, 0, 0, COPYFG);
  692.         if (gc->fill_style == FillOpaqueStippled) {
  693.         FillRect(dcMem, &rect, bgBrush);
  694.         BitBlt(dc, rectangles[i].x, rectangles[i].y,
  695.             rectangles[i].width, rectangles[i].height, dcMem,
  696.             0, 0, COPYBG);
  697.         }
  698.         SelectObject(dcMem, oldBitmap);
  699.         DeleteObject(bitmap);
  700.     }
  701.     
  702.     DeleteDC(dcMem);
  703.     SelectObject(dc, oldBrush);
  704.     DeleteObject(stipple);
  705.     DeleteObject(bgBrush);
  706.     } else {
  707.     for (i = 0; i < nrectangles; i++) {
  708.         TkWinFillRect(dc, rectangles[i].x, rectangles[i].y,
  709.             rectangles[i].width, rectangles[i].height, gc->foreground);
  710.     }
  711.     }
  712.     DeleteObject(brush);
  713.     TkWinReleaseDrawableDC(d, dc, &state);
  714. }
  715.  
  716. /*
  717.  *----------------------------------------------------------------------
  718.  *
  719.  * RenderObject --
  720.  *
  721.  *    This function draws a shape using a list of points, a
  722.  *    stipple pattern, and the specified drawing function.
  723.  *
  724.  * Results:
  725.  *    None.
  726.  *
  727.  * Side effects:
  728.  *    None.
  729.  *
  730.  *----------------------------------------------------------------------
  731.  */
  732.  
  733. static void
  734. RenderObject(dc, gc, points, npoints, mode, pen, func)
  735.     HDC dc;
  736.     GC gc;
  737.     XPoint* points;
  738.     int npoints;
  739.     int mode;
  740.     HPEN pen;
  741.     WinDrawFunc func;
  742. {
  743.     RECT rect;
  744.     HPEN oldPen;
  745.     HBRUSH oldBrush;
  746.     POINT *winPoints = ConvertPoints(points, npoints, mode, &rect);
  747.     
  748.     if ((gc->fill_style == FillStippled
  749.         || gc->fill_style == FillOpaqueStippled)
  750.         && gc->stipple != None) {
  751.  
  752.     TkWinDrawable *twdPtr = (TkWinDrawable *)gc->stipple;
  753.     HDC dcMem;
  754.     LONG width, height;
  755.     HBITMAP oldBitmap;
  756.     int i;
  757.     HBRUSH oldMemBrush;
  758.     
  759.     if (twdPtr->type != TWD_BITMAP) {
  760.         panic("unexpected drawable type in stipple");
  761.     }
  762.  
  763.     /*
  764.      * Grow the bounding box enough to account for wide lines.
  765.      */
  766.  
  767.     if (gc->line_width > 1) {
  768.         rect.left -= gc->line_width;
  769.         rect.top -= gc->line_width;
  770.         rect.right += gc->line_width;
  771.         rect.bottom += gc->line_width;
  772.     }
  773.  
  774.     width = rect.right - rect.left;
  775.     height = rect.bottom - rect.top;
  776.  
  777.     /*
  778.      * Select stipple pattern into destination dc.
  779.      */
  780.     
  781.     SetBrushOrgEx(dc, gc->ts_x_origin, gc->ts_y_origin, NULL);
  782.     oldBrush = SelectObject(dc, CreatePatternBrush(twdPtr->bitmap.handle));
  783.  
  784.     /*
  785.      * Create temporary drawing surface containing a copy of the
  786.      * destination equal in size to the bounding box of the object.
  787.      */
  788.     
  789.     dcMem = CreateCompatibleDC(dc);
  790.     oldBitmap = SelectObject(dcMem, CreateCompatibleBitmap(dc, width,
  791.         height));
  792.     oldPen = SelectObject(dcMem, pen);
  793.     BitBlt(dcMem, 0, 0, width, height, dc, rect.left, rect.top, SRCCOPY);
  794.  
  795.     /*
  796.      * Translate the object for rendering in the temporary drawing
  797.      * surface. 
  798.      */
  799.  
  800.     for (i = 0; i < npoints; i++) {
  801.         winPoints[i].x -= rect.left;
  802.         winPoints[i].y -= rect.top;
  803.     }
  804.  
  805.     /*
  806.      * Draw the object in the foreground color and copy it to the
  807.      * destination wherever the pattern is set.
  808.      */
  809.  
  810.     SetPolyFillMode(dcMem, (gc->fill_rule == EvenOddRule) ? ALTERNATE
  811.         : WINDING);
  812.     oldMemBrush = SelectObject(dcMem, CreateSolidBrush(gc->foreground));
  813.     (*func)(dcMem, winPoints, npoints);
  814.     BitBlt(dc, rect.left, rect.top, width, height, dcMem, 0, 0, COPYFG);
  815.  
  816.     /*
  817.      * If we are rendering an opaque stipple, then draw the polygon in the
  818.      * background color and copy it to the destination wherever the pattern
  819.      * is clear.
  820.      */
  821.  
  822.     if (gc->fill_style == FillOpaqueStippled) {
  823.         DeleteObject(SelectObject(dcMem,
  824.             CreateSolidBrush(gc->background)));
  825.         (*func)(dcMem, winPoints, npoints);
  826.         BitBlt(dc, rect.left, rect.top, width, height, dcMem, 0, 0,
  827.             COPYBG);
  828.     }
  829.  
  830.     SelectObject(dcMem, oldPen);
  831.     DeleteObject(SelectObject(dcMem, oldMemBrush));
  832.     DeleteObject(SelectObject(dcMem, oldBitmap));
  833.     DeleteDC(dcMem);
  834.     } else {
  835.     oldPen = SelectObject(dc, pen);
  836.     oldBrush = SelectObject(dc, CreateSolidBrush(gc->foreground));
  837.     SetROP2(dc, tkpWinRopModes[gc->function]);
  838.  
  839.     SetPolyFillMode(dc, (gc->fill_rule == EvenOddRule) ? ALTERNATE
  840.         : WINDING);
  841.  
  842.     (*func)(dc, winPoints, npoints);
  843.  
  844.     SelectObject(dc, oldPen);
  845.     }
  846.     DeleteObject(SelectObject(dc, oldBrush));
  847. }
  848.  
  849. /*
  850.  *----------------------------------------------------------------------
  851.  *
  852.  * XDrawLines --
  853.  *
  854.  *    Draw connected lines.
  855.  *
  856.  * Results:
  857.  *    None.
  858.  *
  859.  * Side effects:
  860.  *    Renders a series of connected lines.
  861.  *
  862.  *----------------------------------------------------------------------
  863.  */
  864.  
  865. void
  866. XDrawLines(display, d, gc, points, npoints, mode)
  867.     Display* display;
  868.     Drawable d;
  869.     GC gc;
  870.     XPoint* points;
  871.     int npoints;
  872.     int mode;
  873. {
  874.     HPEN pen;
  875.     TkWinDCState state;
  876.     HDC dc;
  877.     
  878.     if (d == None) {
  879.     return;
  880.     }
  881.  
  882.     dc = TkWinGetDrawableDC(display, d, &state);
  883.  
  884.     if (!tkpIsWin32s && (gc->line_width > 1)) {
  885.     LOGBRUSH lb;
  886.     DWORD style;
  887.  
  888.     lb.lbStyle = BS_SOLID;
  889.     lb.lbColor = gc->foreground;
  890.     lb.lbHatch = 0;
  891.  
  892.     style = PS_GEOMETRIC|PS_COSMETIC;
  893.     switch (gc->cap_style) {
  894.         case CapNotLast:
  895.         case CapButt:
  896.         style |= PS_ENDCAP_FLAT; 
  897.         break;
  898.         case CapRound:
  899.         style |= PS_ENDCAP_ROUND; 
  900.         break;
  901.         default:
  902.         style |= PS_ENDCAP_SQUARE; 
  903.         break;
  904.     }
  905.     switch (gc->join_style) {
  906.         case JoinMiter: 
  907.         style |= PS_JOIN_MITER; 
  908.         break;
  909.         case JoinRound:
  910.         style |= PS_JOIN_ROUND; 
  911.         break;
  912.         default:
  913.         style |= PS_JOIN_BEVEL; 
  914.         break;
  915.     }
  916.     pen = ExtCreatePen(style, gc->line_width, &lb, 0, NULL);
  917.     } else {
  918.     pen = CreatePen(PS_SOLID, gc->line_width, gc->foreground);
  919.     }
  920.     RenderObject(dc, gc, points, npoints, mode, pen, Polyline);
  921.     DeleteObject(pen);
  922.     
  923.     TkWinReleaseDrawableDC(d, dc, &state);
  924. }
  925.  
  926. /*
  927.  *----------------------------------------------------------------------
  928.  *
  929.  * XFillPolygon --
  930.  *
  931.  *    Draws a filled polygon.
  932.  *
  933.  * Results:
  934.  *    None.
  935.  *
  936.  * Side effects:
  937.  *    Draws a filled polygon on the specified drawable.
  938.  *
  939.  *----------------------------------------------------------------------
  940.  */
  941.  
  942. void
  943. XFillPolygon(display, d, gc, points, npoints, shape, mode)
  944.     Display* display;
  945.     Drawable d;
  946.     GC gc;
  947.     XPoint* points;
  948.     int npoints;
  949.     int shape;
  950.     int mode;
  951. {
  952.     HPEN pen;
  953.     TkWinDCState state;
  954.     HDC dc;
  955.  
  956.     if (d == None) {
  957.     return;
  958.     }
  959.  
  960.     dc = TkWinGetDrawableDC(display, d, &state);
  961.  
  962.     pen = GetStockObject(NULL_PEN);
  963.     RenderObject(dc, gc, points, npoints, mode, pen, Polygon);
  964.  
  965.     TkWinReleaseDrawableDC(d, dc, &state);
  966. }
  967.  
  968. /*
  969.  *----------------------------------------------------------------------
  970.  *
  971.  * XDrawRectangle --
  972.  *
  973.  *    Draws a rectangle.
  974.  *
  975.  * Results:
  976.  *    None.
  977.  *
  978.  * Side effects:
  979.  *    Draws a rectangle on the specified drawable.
  980.  *
  981.  *----------------------------------------------------------------------
  982.  */
  983.  
  984. void
  985. XDrawRectangle(display, d, gc, x, y, width, height)
  986.     Display* display;
  987.     Drawable d;
  988.     GC gc;
  989.     int x;
  990.     int y;
  991.     unsigned int width;
  992.     unsigned int height;
  993. {
  994.     HPEN pen, oldPen;
  995.     TkWinDCState state;
  996.     HBRUSH oldBrush;
  997.     HDC dc;
  998.  
  999.     if (d == None) {
  1000.     return;
  1001.     }
  1002.  
  1003.     dc = TkWinGetDrawableDC(display, d, &state);
  1004.  
  1005.     pen = CreatePen(PS_SOLID, gc->line_width, gc->foreground);
  1006.     oldPen = SelectObject(dc, pen);
  1007.     oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
  1008.     SetROP2(dc, tkpWinRopModes[gc->function]);
  1009.  
  1010.     Rectangle(dc, x, y, x+width+1, y+height+1);
  1011.  
  1012.     DeleteObject(SelectObject(dc, oldPen));
  1013.     SelectObject(dc, oldBrush);
  1014.     TkWinReleaseDrawableDC(d, dc, &state);
  1015. }
  1016.  
  1017. /*
  1018.  *----------------------------------------------------------------------
  1019.  *
  1020.  * XDrawArc --
  1021.  *
  1022.  *    Draw an arc.
  1023.  *
  1024.  * Results:
  1025.  *    None.
  1026.  *
  1027.  * Side effects:
  1028.  *    Draws an arc on the specified drawable.
  1029.  *
  1030.  *----------------------------------------------------------------------
  1031.  */
  1032.  
  1033. void
  1034. XDrawArc(display, d, gc, x, y, width, height, start, extent)
  1035.     Display* display;
  1036.     Drawable d;
  1037.     GC gc;
  1038.     int x;
  1039.     int y;
  1040.     unsigned int width;
  1041.     unsigned int height;
  1042.     int start;
  1043.     int extent;
  1044. {
  1045.     display->request++;
  1046.  
  1047.     DrawOrFillArc(display, d, gc, x, y, width, height, start, extent, 0);
  1048. }
  1049.  
  1050. /*
  1051.  *----------------------------------------------------------------------
  1052.  *
  1053.  * XFillArc --
  1054.  *
  1055.  *    Draw a filled arc.
  1056.  *
  1057.  * Results:
  1058.  *    None.
  1059.  *
  1060.  * Side effects:
  1061.  *    Draws a filled arc on the specified drawable.
  1062.  *
  1063.  *----------------------------------------------------------------------
  1064.  */
  1065.  
  1066. void
  1067. XFillArc(display, d, gc, x, y, width, height, start, extent)
  1068.     Display* display;
  1069.     Drawable d;
  1070.     GC gc;
  1071.     int x;
  1072.     int y;
  1073.     unsigned int width;
  1074.     unsigned int height;
  1075.     int start;
  1076.     int extent;
  1077. {
  1078.     display->request++;
  1079.  
  1080.     DrawOrFillArc(display, d, gc, x, y, width, height, start, extent, 1);
  1081. }
  1082.  
  1083. /*
  1084.  *----------------------------------------------------------------------
  1085.  *
  1086.  * DrawOrFillArc --
  1087.  *
  1088.  *    This procedure handles the rendering of drawn or filled
  1089.  *    arcs and chords.
  1090.  *
  1091.  * Results:
  1092.  *    None.
  1093.  *
  1094.  * Side effects:
  1095.  *    Renders the requested arc.
  1096.  *
  1097.  *----------------------------------------------------------------------
  1098.  */
  1099.  
  1100. static void
  1101. DrawOrFillArc(display, d, gc, x, y, width, height, start, extent, fill)
  1102.     Display *display;
  1103.     Drawable d;
  1104.     GC gc;
  1105.     int x, y;            /* left top */
  1106.     unsigned int width, height;
  1107.     int start;            /* start: three-o'clock (deg*64) */
  1108.     int extent;            /* extent: relative (deg*64) */
  1109.     int fill;            /* ==0 draw, !=0 fill */
  1110. {
  1111.     HDC dc;
  1112.     HBRUSH brush, oldBrush;
  1113.     HPEN pen, oldPen;
  1114.     TkWinDCState state;
  1115.     int clockwise = (extent < 0); /* non-zero if clockwise */
  1116.     int xstart, ystart, xend, yend;
  1117.     double radian_start, radian_end, xr, yr;
  1118.  
  1119.     if (d == None) {
  1120.     return;
  1121.     }
  1122.  
  1123.     dc = TkWinGetDrawableDC(display, d, &state);
  1124.  
  1125.     SetROP2(dc, tkpWinRopModes[gc->function]);
  1126.  
  1127.     /*
  1128.      * Compute the absolute starting and ending angles in normalized radians.
  1129.      * Swap the start and end if drawing clockwise.
  1130.      */
  1131.  
  1132.     start = start % (64*360);
  1133.     if (start < 0) {
  1134.     start += (64*360);
  1135.     }
  1136.     extent = (start+extent) % (64*360);
  1137.     if (extent < 0) {
  1138.     extent += (64*360);
  1139.     }
  1140.     if (clockwise) {
  1141.     int tmp = start;
  1142.     start = extent;
  1143.     extent = tmp;
  1144.     }
  1145.     radian_start = XAngleToRadians(start);
  1146.     radian_end = XAngleToRadians(extent);
  1147.  
  1148.     /*
  1149.      * Now compute points on the radial lines that define the starting and
  1150.      * ending angles.  Be sure to take into account that the y-coordinate
  1151.      * system is inverted.
  1152.      */
  1153.  
  1154.     xr = x + width / 2.0;
  1155.     yr = y + height / 2.0;
  1156.     xstart = (int)((xr + cos(radian_start)*width/2.0) + 0.5);
  1157.     ystart = (int)((yr + sin(-radian_start)*height/2.0) + 0.5);
  1158.     xend = (int)((xr + cos(radian_end)*width/2.0) + 0.5);
  1159.     yend = (int)((yr + sin(-radian_end)*height/2.0) + 0.5);
  1160.  
  1161.     /*
  1162.      * Now draw a filled or open figure.  Note that we have to
  1163.      * increase the size of the bounding box by one to account for the
  1164.      * difference in pixel definitions between X and Windows.
  1165.      */
  1166.  
  1167.     pen = CreatePen(PS_SOLID, gc->line_width, gc->foreground);
  1168.     oldPen = SelectObject(dc, pen);
  1169.     if (!fill) {
  1170.     /*
  1171.      * Note that this call will leave a gap of one pixel at the
  1172.      * end of the arc for thin arcs.  We can't use ArcTo because
  1173.      * it's only supported under Windows NT.
  1174.      */
  1175.  
  1176.     Arc(dc, x, y, x+width+1, y+height+1, xstart, ystart, xend, yend);
  1177.     } else {
  1178.     brush = CreateSolidBrush(gc->foreground);
  1179.     oldBrush = SelectObject(dc, brush);
  1180.     if (gc->arc_mode == ArcChord) {
  1181.         Chord(dc, x, y, x+width+1, y+height+1, xstart, ystart, xend, yend);
  1182.     } else if ( gc->arc_mode == ArcPieSlice ) {
  1183.         Pie(dc, x, y, x+width+1, y+height+1, xstart, ystart, xend, yend);
  1184.     }
  1185.     DeleteObject(SelectObject(dc, oldBrush));
  1186.     }
  1187.     DeleteObject(SelectObject(dc, oldPen));
  1188.     TkWinReleaseDrawableDC(d, dc, &state);
  1189. }
  1190.  
  1191. /*
  1192.  *----------------------------------------------------------------------
  1193.  *
  1194.  * TkScrollWindow --
  1195.  *
  1196.  *    Scroll a rectangle of the specified window and accumulate
  1197.  *    a damage region.
  1198.  *
  1199.  * Results:
  1200.  *    Returns 0 if the scroll genereated no additional damage.
  1201.  *    Otherwise, sets the region that needs to be repainted after
  1202.  *    scrolling and returns 1.
  1203.  *
  1204.  * Side effects:
  1205.  *    Scrolls the bits in the window.
  1206.  *
  1207.  *----------------------------------------------------------------------
  1208.  */
  1209.  
  1210. int
  1211. TkScrollWindow(tkwin, gc, x, y, width, height, dx, dy, damageRgn)
  1212.     Tk_Window tkwin;        /* The window to be scrolled. */
  1213.     GC gc;            /* GC for window to be scrolled. */
  1214.     int x, y, width, height;    /* Position rectangle to be scrolled. */
  1215.     int dx, dy;            /* Distance rectangle should be moved. */
  1216.     TkRegion damageRgn;        /* Region to accumulate damage in. */
  1217. {
  1218.     HWND hwnd = TkWinGetHWND(Tk_WindowId(tkwin));
  1219.     RECT scrollRect;
  1220.  
  1221.     scrollRect.left = x;
  1222.     scrollRect.top = y;
  1223.     scrollRect.right = x + width;
  1224.     scrollRect.bottom = y + height;
  1225.     return (ScrollWindowEx(hwnd, dx, dy, &scrollRect, NULL, (HRGN) damageRgn,
  1226.         NULL, 0) == NULLREGION) ? 0 : 1;
  1227. }
  1228.  
  1229. /*
  1230.  *----------------------------------------------------------------------
  1231.  *
  1232.  * TkWinFillRect --
  1233.  *
  1234.  *    This routine fills a rectangle with the foreground color
  1235.  *    from the specified GC ignoring all other GC values.  This
  1236.  *    is the fastest way to fill a drawable with a solid color.
  1237.  *
  1238.  * Results:
  1239.  *    None.
  1240.  *
  1241.  * Side effects:
  1242.  *    Modifies the contents of the DC drawing surface.
  1243.  *
  1244.  *----------------------------------------------------------------------
  1245.  */
  1246.  
  1247. void
  1248. TkWinFillRect(dc, x, y, width, height, pixel)
  1249.     HDC dc;
  1250.     int x, y, width, height;
  1251.     int pixel;
  1252. {
  1253.     RECT rect;
  1254.     COLORREF oldColor;
  1255.  
  1256.     rect.left = x;
  1257.     rect.top = y;
  1258.     rect.right = x + width;
  1259.     rect.bottom = y + height;
  1260.     oldColor = SetBkColor(dc, (COLORREF)pixel);
  1261.     SetBkMode(dc, OPAQUE);
  1262.     ExtTextOut(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
  1263.     SetBkColor(dc, oldColor);
  1264. }
  1265.